///////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2009.
// -------------------------------------------------------------------------
//  File name:   LMG_ExtractParameters.cpp
//  Version:     v1.00
//  Created:     07/06/2009 by Jaewon Jung
//  Description: Locomotion Group utility functions
// -------------------------------------------------------------------------
//
///////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "CharacterManager.h"
#include "LMG.h"
#include "ModelAnimationSet.h"
#include "AnimationManager.h"
#include "LoaderDBA.h"

namespace LMG
{
	namespace _private
	{
		IController* GAH_GetRootController(CAnimationSet* pAnimSet, GlobalAnimationHeaderCAF& rGAH, uint32 globalID, const char* pAnimName)
		{
			const CModelJoint* pRootJoint	= &pAnimSet->m_pModel->m_ModelSkeleton.m_arrModelJoints[0];
			IController* pController = rGAH.GetControllerByJointCRC32(pRootJoint->m_nJointCRC32);
			if (pController==0)
				rGAH.LoadControllersCAF(pRootJoint->m_nJointCRC32);
			pController = rGAH.GetControllerByJointCRC32(pRootJoint->m_nJointCRC32);
			if (pController==0)
			{
				const char* pModelName = pAnimSet->m_pModel->GetFilePath();
				g_pISystem->Warning( VALIDATOR_MODULE_ANIMATION,VALIDATOR_WARNING,
					VALIDATOR_FLAG_FILE, pModelName, "LMG is invalid. Locomotion-asset '%s' not in memory ",pAnimName );

				rGAH.InvalidateAssetLMG();
				return 0;
			}

			return pController;
		}

		void GAH_ComputeVelocity(GlobalAnimationHeaderCAF& rGAH, const Vec3& travelDir, BSAnimationLMG& bsAnimation)
		{
			bsAnimation.m_qVelocity = travelDir*rGAH.m_fMoveSpeed;
		}

		void GAH_ComputeTurn(GlobalAnimationHeaderCAF& rCAF, int GAID, IController* pRootCtl222, BSAnimationLMG& bsAnimation)
		{
			Quat startRot;	startRot.SetIdentity();
			Quat middleRot; middleRot.SetIdentity();
			Quat endRot = rCAF.m_StartLocation.q.GetInverted()*rCAF.m_EndLocation.q;


			middleRot.SetSlerp(startRot, endRot, 0.5f);

		//	pRootCtl->GetO( rGAH.NTime2KTime(0), startRot);
		//	pRootCtl->GetO( rGAH.NTime2KTime(0.5f), middleRot);
		//	pRootCtl->GetO( rGAH.NTime2KTime(1), endRot);

			const Vec3 startDir = startRot.GetColumn1();
			const Vec3 middleDir = middleRot.GetColumn1();
			const Vec3 endDir = endRot.GetColumn1();

			const f32 leftAngle = Ang3::CreateRadZ(startDir, middleDir);
			const f32 rightAngle = Ang3::CreateRadZ(middleDir, endDir);

			f32 angle = leftAngle + rightAngle;

			f32 fAssetTurn = rCAF.m_fAssetTurn;
			f32 fTurnSpeed = rCAF.m_fTurnSpeed;
			f32 duration   = rCAF.m_fEndSec - rCAF.m_fStartSec;
			duration=max(duration,SECONDS_PER_TICK);

			rCAF.m_fAssetTurn = angle;
			rCAF.m_fTurnSpeed = angle / duration;
			
		//	assert( fabsf(rCAF.m_fAssetTurn-fAssetTurn)<0.0001f ); 
		//	assert( fabsf(rCAF.m_fTurnSpeed-fTurnSpeed)<0.0001f ); 

			uint32 ddd=0;
		}

		Vec3 GetTravelDir(int GAID)
		{
			GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[GAID];
			QuatT k1 = rCAF.m_StartLocation.GetInverted()*rCAF.m_EndLocation;
			return k1.t.GetNormalizedSafe( Vec3(0,1,0) );
		}

		template <bool bVelocity, bool bUseTravelDir, bool bTurn>
		void GAH_Compute(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			assert(0);
		}

		template <>
		void GAH_Compute<true, true, true>(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_ComputeVelocity(rGAH, GetTravelDir(GAID),bsAnimation);
			GAH_ComputeTurn(rGAH, GAID, pRootCtl,bsAnimation);
		}

		template <>
		void GAH_Compute<true, false, true>(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_ComputeVelocity(rGAH, Vec3(0,1,0), bsAnimation);
			GAH_ComputeTurn(rGAH, GAID, 0, bsAnimation);
		}

		template <>
		void GAH_Compute<true, true, false>(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_ComputeVelocity(rGAH, GetTravelDir(GAID), bsAnimation);
		}

		template <>
		void GAH_Compute<true, false, false>(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_ComputeVelocity(rGAH,Vec3(0,1,0), bsAnimation);
		}

		template <>
		void GAH_Compute<false, false, true>(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_ComputeTurn(rGAH,GAID,pRootCtl, bsAnimation);
		}

		void GAH_ComputeForCLMB(GlobalAnimationHeaderCAF& rGAH, int GAID, IController* pRootCtl, BSAnimationLMG& bsAnimation)
		{
			GAH_Compute<true, false, true>(rGAH, GAID, pRootCtl, bsAnimation);

			Vec3 startPos, endPos;
			pRootCtl->GetP( rGAH.NTime2KTime(0), startPos);
			pRootCtl->GetP( rGAH.NTime2KTime(1), endPos);
			bsAnimation.m_Position.z = endPos.z - startPos.z;
		}

		typedef void ComputeFuncType(GlobalAnimationHeaderCAF&, int, IController*, BSAnimationLMG&);
		template <ComputeFuncType Compute>
		void ExtractParametersTemplate(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& rGHLMG)
		{
			uint32 numExamples = rGHLMG.m_arrBSAnimations.size();
			for (uint32 i=0; i<numExamples; i++)
			{
				int32 animID = pAnimSet->GetAnimIDByCRC( rGHLMG.m_arrBSAnimations[i].m_animName.m_CRC32 );
				assert(animID >= 0);
				int32 globalID = pAnimSet->GetGlobalIDByAnimID_Fast( animID );
				assert(globalID >= 0);

				GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[globalID];
				Compute(rGAH, globalID, 0, rGHLMG.m_arrBSAnimations[i]);
			}
		}

		void ExtractParametersForIdleRot(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, false, true> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForStrafingMotion(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& rGHLMG)
		{
			uint32 numAssets = rGHLMG.m_arrBSAnimations.size();
			for (uint32 i=0; i<numAssets; i++)
			{
				int32 animID = pAnimSet->GetAnimIDByCRC(rGHLMG.m_arrBSAnimations[i].m_animName.m_CRC32);
				assert(animID>=0);
				if (animID < 0)
					continue;

				int32 globalID = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID>=0);
				if (globalID < 0)
					continue;
				GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[globalID];

				uint32 OnDemand	=	rGAH.IsAssetOnDemand();
				f32 fStart			= rGAH.m_fStartSec;
				f32 fEnd				= rGAH.m_fEndSec;
				f32 duration		= fEnd-fStart;

				const CModelJoint* pModelJoint	= &pAnimSet->m_pModel->m_ModelSkeleton.m_arrModelJoints[0];
				GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[globalID];

				QuatT k1 = rCAF.m_StartLocation.GetInverted()*rCAF.m_EndLocation;
				const bool bDistinctTravelDirs = (k1.t|k1.t) > (0.01f*0.01f);
				const Vec3 TravelDir = k1.t.GetNormalizedSafe(Vec3(0,1,0));
				ANIM_ASSET_CHECK_TRACE(bDistinctTravelDirs, ("LMG is invalid. Locomotion-asset '%s' in file '%s' has equivalent travel directions.", rGHLMG.m_arrBSAnimations[i].m_animName.GetName_DEBUG(), pAnimSet->m_pModel->GetFilePath().c_str()));
				if(!bDistinctTravelDirs)
				{
					rGHLMG.InvalidateAssetLMG();
					continue;
				}

				f32 speed = g_AnimationManager.m_arrGlobalCAF[globalID].m_fMoveSpeed;
				if (speed<0.1f)
				{
					const char* pModelName = pAnimSet->m_pModel->GetFilePath();
					g_pISystem->Warning( VALIDATOR_MODULE_ANIMATION,VALIDATOR_WARNING,	VALIDATOR_FLAG_FILE, pModelName, "LMG is invalid. Locomotion-asset '%s' has a speed: %d",rGHLMG.m_arrBSAnimations[i].m_animName.GetName_DEBUG(),speed );
					rGHLMG.InvalidateAssetLMG();
					continue;
				}
			//	g_AnimationManager.m_arrGlobalCAF[globalID].m_vVelocityXYZ = TravelDir * speed;
				rGHLMG.m_arrBSAnimations[i].m_qVelocity = TravelDir * speed;


				Quat rot0; rot0.SetIdentity();
				Quat rot1; rot1=k1.q;

				Vec3 v0=rot0.GetColumn1();
				Vec3 v1=rot1.GetColumn1();
				f32 radiant = Ang3::CreateRadZ(v0,v1);

				f32 fTurnSec = radiant/duration;
			//	g_AnimationManager.m_arrGlobalCAF[globalID].m_fAssetTurn =	0.0f;//radiant;
			//	g_AnimationManager.m_arrGlobalCAF[globalID].m_fTurnSpeed = 0.0f; //fTurnSec;
				if (fabsf(fTurnSec)>0.3f)
				{
				//	g_AnimationManager.m_arrGlobalCAF[globalID].m_vVelocityXYZ	=	Vec3(0,speed,0);
					rGHLMG.m_arrBSAnimations[i].m_qVelocity=Vec3(0,speed,0);
				}
			}
		}
		void ExtractParametersForSTH2(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			uint32 numAssets = globalAnimHeader.m_arrBSAnimations.size();
			//not a perfect solution, but it will do for now
			{
				int32 animID = pAnimSet->GetAnimIDByCRC(globalAnimHeader.m_arrBSAnimations[21].m_animName.m_CRC32);
				assert(animID>=0);
				int32 globalID0 = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID0>=0);
				f32 radiant0 = g_AnimationManager.m_arrGlobalCAF[globalID0].m_fAssetTurn;
				f32 turnsec0 = g_AnimationManager.m_arrGlobalCAF[globalID0].m_fTurnSpeed;
				//assert(turnsec0>0.5f);

				animID = pAnimSet->GetAnimIDByCRC(globalAnimHeader.m_arrBSAnimations[23].m_animName.m_CRC32);
				assert(animID>=0);
				int32 globalID1 = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID1>=0);
				f32 radiant1 = g_AnimationManager.m_arrGlobalCAF[globalID1].m_fAssetTurn;
				f32 turnsec1 = g_AnimationManager.m_arrGlobalCAF[globalID1].m_fTurnSpeed;
				//assert(turnsec1>0.5f);

			//	g_AnimationManager.m_arrGlobalCAF[globalID0].m_fAssetTurn=(radiant0+radiant1)*0.5f;
			//	g_AnimationManager.m_arrGlobalCAF[globalID0].m_fTurnSpeed=(turnsec0+turnsec1)*0.5f;

			//	g_AnimationManager.m_arrGlobalCAF[globalID1].m_fAssetTurn=(radiant0+radiant1)*0.5f;
			//	g_AnimationManager.m_arrGlobalCAF[globalID1].m_fTurnSpeed=(turnsec0+turnsec1)*0.5f;
			}

			{
				int32 animID = pAnimSet->GetAnimIDByCRC(globalAnimHeader.m_arrBSAnimations[22].m_animName.m_CRC32);
				assert(animID>=0);
				int32 globalID0 = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID0>=0);
				f32 radiant0 = g_AnimationManager.m_arrGlobalCAF[globalID0].m_fAssetTurn;
				f32 turnsec0 = g_AnimationManager.m_arrGlobalCAF[globalID0].m_fTurnSpeed;
				//assert(turnsec0<-0.5f);

				animID = pAnimSet->GetAnimIDByCRC(globalAnimHeader.m_arrBSAnimations[24].m_animName.m_CRC32);
				assert(animID>=0);				
				int32 globalID1 = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID1>=0);
				f32 radiant1 = g_AnimationManager.m_arrGlobalCAF[globalID1].m_fAssetTurn;
				f32 turnsec1 = g_AnimationManager.m_arrGlobalCAF[globalID1].m_fTurnSpeed;
				//assert(turnsec0<-0.5f);

			//	g_AnimationManager.m_arrGlobalCAF[globalID0].m_fAssetTurn=(radiant0+radiant1)*0.5f;
			//	g_AnimationManager.m_arrGlobalCAF[globalID0].m_fTurnSpeed=(turnsec0+turnsec1)*0.5f;

			//	g_AnimationManager.m_arrGlobalCAF[globalID1].m_fAssetTurn=(radiant0+radiant1)*0.5f;
			//	g_AnimationManager.m_arrGlobalCAF[globalID1].m_fTurnSpeed=(turnsec0+turnsec1)*0.5f;
			}
		}

		void ExtractParametersForIdleStep(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, true, false> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForTurningMotion(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, false, false> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForPROT(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, false, true> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForPUSH(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, true, true> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForSCAL(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<true, false, true> >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForCLMB(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_ComputeForCLMB >(pAnimSet, globalAnimHeader);
		}

		void ExtractParametersForCOOP(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& rGHLMG)
		{
			DynArray<BSAnimationLMG>& bsAnimations = rGHLMG.m_arrBSAnimations;
			for (uint32 i = 0; i < (uint32)bsAnimations.size(); i++)
			{
				int32 animID = pAnimSet->GetAnimIDByCRC(bsAnimations[i].m_animName.m_CRC32);
				assert(animID>=0);
				int32 globalID = pAnimSet->GetGlobalIDByAnimID_Fast(animID);
				assert(globalID >= 0);

				GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[globalID];
				IController* pRootCtl = GAH_GetRootController(pAnimSet,rGAH,globalID,bsAnimations[i].m_animName.GetName_DEBUG());
				assert(pRootCtl);
				GAH_ComputeTurn(rGAH, globalID, pRootCtl,bsAnimations[i]);
				rGHLMG.m_arrBSAnimations[i].m_qVelocity=Vec3(0,1,0)*rGAH.m_fMoveSpeed;
			}
		}

		void ExtractParametersForIdleToMove(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
		{
			ExtractParametersTemplate< GAH_Compute<false, false, true> >(pAnimSet, globalAnimHeader);
		}


		uint32 GetAnimIDAndHeadersLMG(const CAnimationSet* pAnimSet, const GlobalAnimationHeaderLMG& rGlobalAnimHeader, int32* nAnimID, const ModelAnimationHeader** pAnim)
		{
			nAnimID[0]=-1; 
			nAnimID[1]=-1;
			nAnimID[2]=-1; 

			nAnimID[3]=-1;
			nAnimID[4]=-1; 
			nAnimID[5]=-1;

			nAnimID[6]=-1;
			nAnimID[7]=-1;
			nAnimID[8]=-1;

			uint32 num=0;
			if (rGlobalAnimHeader.IsAssetLMG())
			{
				num = rGlobalAnimHeader.m_arrBSAnimations.size();
				for (uint32 i=0; i<num; i++)
				{
					nAnimID[i] = pAnimSet->GetAnimIDByCRC( rGlobalAnimHeader.m_arrBSAnimations[i].m_animName.m_CRC32 );
					pAnim[i] = pAnimSet->GetModelAnimationHeader(nAnimID[i]);
				}
			}

			return num;
		}


	} // namespace _private
} // namespace LMG

namespace LMG
{
	bool IsStrafingLMGCode(uint32 nBC)
	{
		uint32 nS__1 = *(uint32*)"S__1"; // strafe6,               one speed
		uint32 nM__1 = *(uint32*)"M__1"; // strafe8,               one speed
		uint32 nS__2 = *(uint32*)"S__2"; // strafe,               two speeds
		uint32 nS_H2 = *(uint32*)"S_H2"; // strafe, slope,        two speeds
		uint32 nST_2 = *(uint32*)"ST_2"; // strafe+curving,       two speeds
		uint32 n_TH2 = *(uint32*)"_TH2"; //        curving+slope, two speeds
		uint32 nSTH2 = *(uint32*)"STH2"; // strafe+curve+slope,   two speeds
		uint32 nSTF1 = *(uint32*)"STF1"; // strafe, one speed
		uint32 nSTF2 = *(uint32*)"STF2"; // strafe, two speeds

		uint32 nT_WS = *(uint32*)"T_WS"; // [artemk] tactical_walk_strafe. S__1 for tactical moves

		// OBSOLETE
		uint32 nSUD2 = *(uint32*)"SUD2";
		uint32 nSTHX = *(uint32*)"STHX";

		bool isStrafingLMG = ( nBC==nS__1 || nBC==nM__1 || nBC==nS__2 || nBC==nS_H2 || nBC==nST_2 || nBC==n_TH2 || nBC==nSTH2 || nBC==nSTHX || nBC==nSTF1 || nBC==nSTF2 || nBC==nSUD2 || nBC==nT_WS );
		return isStrafingLMG;
	}

	bool IsValidBlendCode( uint32 blendCode )
	{
#define DRY(x) if ( *(uint32*)(#x) == blendCode ) { return true; }
#include "LMG_Types.inc"
#undef DRY
		return false;
	}

	void ExtractParameters(CAnimationSet* pAnimSet, GlobalAnimationHeaderLMG& globalAnimHeader)
	{
		assert(pAnimSet);
		uint32 nBC = globalAnimHeader.m_nBlendCodeLMG;
		DynArray<BSAnimationLMG> & bsAnimations = globalAnimHeader.m_arrBSAnimations;

		uint32 nIROT = *(uint32*)"IROT";
		uint32 nTSTP = *(uint32*)"TSTP";

		uint32 nSTH2 = *(uint32*)"STH2"; // strafe+curve+slope,   two speeds

		uint32 nISTP = *(uint32*)"ISTP";
		uint32 nT_IS = *(uint32*)"T_IS"; // [artemk] tactical_idle_step. ISTP for tactical moves

		uint32 nT_IA = *(uint32*)"T_IA";

		uint32 nFLR1 = *(uint32*)"FLR1"; 
		uint32 nFLR2 = *(uint32*)"FLR2"; 
		uint32 nFLR3 = *(uint32*)"FLR3"; 

		uint32 nUDH1 = *(uint32*)"UDH1"; 
		uint32 nUDH2 = *(uint32*)"UDH2"; 
		uint32 nUDH3 = *(uint32*)"UDH3";
				
		uint32 PROT = *(uint32*)"PROT";
		
		uint32 PUSH = *(uint32*)"PUSH";

		uint32 SCAL = *(uint32*)"SCAL";

		uint32 CLMB = *(uint32*)"CLMB";

		uint32 COOP = *(uint32*)"COOP";

		uint32 nI2M1 = *(uint32*)"I2M1"; 
		uint32 nI2M2 = *(uint32*)"I2M2"; 

		uint32 nXIM2 = *(uint32*)"XIM2"; 
		uint32 nI2MT = *(uint32*)"I2MT"; 

		if (nBC==nIROT || nBC==nTSTP)
			_private::ExtractParametersForIdleRot(pAnimSet, globalAnimHeader);
		else if (IsStrafingLMGCode(nBC))
		{
			_private::ExtractParametersForStrafingMotion(pAnimSet, globalAnimHeader);
			if (nBC==nSTH2)
				_private::ExtractParametersForSTH2(pAnimSet, globalAnimHeader);
		}
		else if ( nBC==nISTP || nBC==nT_IS )
			_private::ExtractParametersForIdleStep(pAnimSet, globalAnimHeader);
		else if (nBC == nT_IA)
		{
			// [artemk]: do not use any parameters for this blend type
		}
		else if (nBC==nFLR1 ||	nBC==nFLR2 ||	nBC==nFLR3 || nBC==nUDH1 || nBC==nUDH2 ||	nBC==nUDH3 )
			_private::ExtractParametersForTurningMotion(pAnimSet, globalAnimHeader);
		else if (nBC==PROT )
			_private::ExtractParametersForPROT(pAnimSet, globalAnimHeader);
		else if (nBC == PUSH)
			_private::ExtractParametersForPUSH(pAnimSet, globalAnimHeader);
		else if (nBC==SCAL )
			_private::ExtractParametersForSCAL(pAnimSet, globalAnimHeader);
		else if (nBC==CLMB )
			_private::ExtractParametersForCLMB(pAnimSet, globalAnimHeader);
		else if (nBC==COOP )
			_private::ExtractParametersForCOOP(pAnimSet, globalAnimHeader);
		if (nBC==nI2M1 || nBC==nI2M2 || nBC==nI2MT)
			_private::ExtractParametersForIdleToMove(pAnimSet, globalAnimHeader);
	}

	SParametric			*g_parametricPool  = NULL;
	bool					  *g_usedParametrics = NULL;
	int32						 g_totalParametrics = 0;

	void InitialiseRuntimePool()
	{
		const int numParametrics = Console::GetInst().ca_ParametricPoolSize;

		if (numParametrics != g_totalParametrics)
		{
			delete [] g_parametricPool;
			delete [] g_usedParametrics;
			g_parametricPool = new SParametric[numParametrics];
			g_usedParametrics = new bool[numParametrics];
			g_totalParametrics = numParametrics;
		}
		memset(g_usedParametrics, 0, numParametrics);
	}

	void DestroyRuntimePool()
	{
		delete [] g_parametricPool;
		delete [] g_usedParametrics;
		g_parametricPool = NULL;
		g_usedParametrics = NULL;
		g_totalParametrics = 0;
	}

	SParametric *AllocateRuntimeParametric()
	{
		for (int i=0; i<g_totalParametrics; i++)
		{
			if (!g_usedParametrics[i])
			{
				SParametric *ret = &g_parametricPool[i];
				g_usedParametrics[i] = 1;
				new (ret) SParametric;
				return ret;
			}
		}

		CRY_ASSERT_TRACE(0, ("Run out of free parametric slots! If current usage is typical increase pool size via ca_ParametricPoolSize. Current Size: %d", g_totalParametrics));
		CryLogAlways("Run out of free parametric slots! If current usage is typical increase pool size via ca_ParametricPoolSize. Current Size: %d", g_totalParametrics);
		return NULL;
	}

	void FreeRuntimeParametric(SParametric *param)
	{
		if (param)
		{
			ptrdiff_t slot = param - g_parametricPool;
			if ((slot >= 0) && (slot < g_totalParametrics))
			{
				CRY_ASSERT_TRACE(g_usedParametrics[slot], ("Releasing unallocated parametric %d", slot));

				g_usedParametrics[slot] = 0;
			}
			else
			{
				CRY_ASSERT_TRACE(0, ("Releasing unpooled parametric %d", param));
			}
		}
	}

	SParametric* BuildRuntimeStructLMG(const CAnimationSet* pAnimSet, const ModelAnimationHeader* pAnim0, int nID)
	{
		int32 nAnimID[MAX_LMG_ANIMS]; 
		const ModelAnimationHeader* pAnimHeaders[MAX_LMG_ANIMS];

		uint32 nGlobalAnimId = pAnim0->m_nGlobalAnimId;
		if (pAnim0->m_nAssetType==LMG_File)
		{
			GlobalAnimationHeaderLMG& rGlobalAnimHeader0 = g_AnimationManager.m_arrGlobalLMG[nGlobalAnimId];
			assert(rGlobalAnimHeader0.IsAssetLMG());
			const int32 numAnims = _private::GetAnimIDAndHeadersLMG(pAnimSet, rGlobalAnimHeader0, &nAnimID[0],&pAnimHeaders[0]);
			SParametric *lmg = AllocateRuntimeParametric();

			if (lmg)
			{
				lmg->m_nParametricID = nID;
				lmg->m_numAnims			 =	numAnims;
				for (int32 i=0; i<numAnims; i++)
				{
					if (pAnimHeaders[i])
					{
						lmg->m_nAnimID[i]					=	nAnimID[i];
						lmg->m_nSegmentCounter[i]	= 0;
					}
					else
						assert(0);
				}
			}

			return lmg;
		}

		assert(0);
		return NULL;
	}



} // namespace LMG
